home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume11 / number < prev    next >
Encoding:
Internet Message Format  |  1987-08-31  |  37.1 KB

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v11i028:  Arabic numerals to multi-lingual natural language
  5. Message-ID: <1334@uunet.UU.NET>
  6. Date: 2 Sep 87 00:21:36 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1629
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: mcvax!imag!scott (Scott Deerwester)
  12. Posting-number: Volume 11, Issue 28
  13. Archive-name: number
  14.  
  15. [  This is great!  The comment at the start of the source is almost as good.
  16.    Beware of the "ln" calls this archive makes...  -r$  ]
  17.  
  18. #! /bin/sh
  19. # This is a shell archive, meaning:
  20. # 1. Remove everything above the #! /bin/sh line.
  21. # 2. Save the resulting text in a file.
  22. # 3. Execute the file with /bin/sh (not csh) to create the files:
  23. #    README
  24. #    Makefile
  25. #    number.6
  26. #    number.c
  27. #    lang
  28. export PATH; PATH=/bin:$PATH
  29. echo shar: extracting "'README'" '(6275 characters)'
  30. if test -f 'README'
  31. then
  32.     echo shar: will not over-write existing file "'README'"
  33. else
  34. sed 's/^X//' << \SHAR_EOF > 'README'
  35. X    ::::    Description    ::::
  36. X
  37. XThis version of number was inspired from the standard
  38. Xversion in /usr/games, but with a big difference:  It
  39. Xknows how to count in a *lot* of languages, and can
  40. Xbe taught almost anything that it doesn't already know.
  41. XThe information on how to count in a given language
  42. Xis given in a grammar, written in a meta-language described
  43. Xa little later.  Grammars exist, as of this moment, for:
  44. X
  45. XCantonese        French        Japanese    Spanish
  46. XChinese (Mandarin)    Gaellic (Irish)    Malinke        Susu
  47. XEnglish            German        Pular        Vietnamese
  48. XEsperanto        Italian        Romanian
  49. X
  50. XIt takes about twenty minutes with a native speaker to
  51. Xwrite a grammar, once you understand how to do so.  Instructions
  52. Xon how to write a grammar are included at the end of this
  53. Xfile.  It is also highly recommended that you study some
  54. Xof the existing grammars before attempting your own.
  55. X
  56. X    ::::    Installation    ::::
  57. X
  58. X- Make a directory for this package, and cd to it.
  59. X- Run 'sh' on the file that you put this shell archive
  60. X  in in order to extract all of the files in it.
  61. X- Edit the Makefile to indicate where you want the
  62. X  executable, and the grammar files to be kept.
  63. X
  64. X** Important: THIS MUST BE DONE BEFORE YOU COMPILE NUMBER!
  65. X
  66. X- Type 'make install'
  67. X
  68. X    ::::    Adding languages    ::::
  69. X
  70. X** Note:  If all you want to do is use number, you can skip the
  71. X      rest of this file.
  72. X
  73. XThe grammar files used by number contain rules that
  74. Xnumber uses to translate numbers into words.  The
  75. Xrules are generally of the form:
  76. X
  77. Xn    rules
  78. X
  79. Xwhere 'n' is the "base" number, separated by a single tab from
  80. Xthe rule per se.  The rules must be in ascending order of
  81. Xbase number.  The basic algorithm that number uses to
  82. Xtranslate a number to words is to find the rule with
  83. Xthe largest base that is smaller than the number, and
  84. Xevaluate the rule for that base, given the number.  For
  85. Xexample, one might have the rule:
  86. X
  87. X5    "five"
  88. X
  89. Xwhich, if the number being translated were 5, would cause
  90. Xthe rule "five" to be evaluated.  In this case, the rule
  91. Xis a simple string, which would be printed.  Rules may
  92. Xcontain:
  93. X
  94. X- Strings, delimited by double quotes, which are simply printed.
  95. X- Spaces, which are printed as well.
  96. X- A number, which causes the number to be spelled.
  97. X- The following special characters, with the meanings:
  98. X  /  Spell the number divided by the base.
  99. X  %  Spell the number modulus the base.
  100. X- A conditional, described below.
  101. X- A single character macro.
  102. X- A comma, which functions as a no-op.
  103. X
  104. XIn addition, grammars contain macro definitions, and may
  105. Xcontain lines of comments, which have a '#' in the first
  106. Xcolumn.  Rules may be continued across multiple lines by
  107. Xterminating the line with a '\'.  The next line must
  108. Xbegin with a tab character.
  109. X
  110. XConditionals have the following syntax:
  111. X
  112. X(L C R    rule)
  113. X
  114. Xwith a tab separating the 'R' from the rule.  L and R
  115. Xare either numbers, or one of the characters:
  116. X
  117. X/    Number divided by base.
  118. X%    Number modulus base.
  119. XB    Base.
  120. X#    Number.
  121. XL    Recursion level.
  122. X
  123. XC is one of '<', '>', '=' or '~', meaning less than,
  124. Xgreater than, equal to, or not equal to, respectively.
  125. XThe following (common) rule, taken from the grammar
  126. Xfor Esperanto, expresses the fact that for units
  127. Xof 10, the number divided by 10 is only added before
  128. Xthe word for 10 if is greater than 1:
  129. X
  130. X10    (/ > 1    /)"dek" %
  131. X
  132. XThus, if 23 were being evaluated, the conditional would
  133. Xcheck to see if 23 / 10 is greater than 1, and, since it
  134. Xis, evaluate the rule '/' causing 2 to be spelled.  Given
  135. Xthe following grammar:
  136. X
  137. X0    "zero"
  138. X1    "unu"
  139. X2    "du"
  140. X3    "tri"
  141. X4    "kvar"
  142. X5    "kvin"
  143. X6    "ses"
  144. X7    "sep"
  145. X8    "ok"
  146. X9    "na[bre]u"
  147. X10    (/ > 1    /)"dek" %
  148. X100    (/ > 1    /) "cent" %
  149. X
  150. Xand the number 23, the following would happen:
  151. X
  152. X- Select rule for base 10, number 23, since 10 is the largest
  153. X  base that is smaller than 23.
  154. X  - Evaluate the conditional '(/ > 1    /)'.
  155. X    - Evaluate / -> 23 / 10 -> 2.
  156. X    - Evaluate 2 > 1 -> TRUE.
  157. X    - Evaluate / -> 23 / 10 -> 2.
  158. X      - Evaluate rule for base 2, number 2.
  159. X    - Print "du".
  160. X  - Print "dek".
  161. X  - Print " ".
  162. X  - Evaluate % -> 23 % 10 -> 3.
  163. X    - Evaluate rule for base 3, number 3.
  164. X      - Print "tri"
  165. X
  166. XThe net result is that "dudek tri" is printed.
  167. X
  168. X    ::::    Macros    ::::
  169. X
  170. XA macro is defined by the following syntax:
  171. X
  172. X/    c    rule
  173. X
  174. Xwhere c is any letter except L and B.  (Other characters
  175. Xare allowed as well, but don't bump into special characters...)
  176. XIn the grammar given above, for Esperanto, we could have
  177. Xused a macro to simplify the rules for 10 and 100, thus:
  178. X
  179. X/    d    (/ > 1    /)
  180. X10    d"dek" %
  181. X100    d "cent" %
  182. X
  183. XThe following is about the most complicated piece of
  184. Xcode in a grammar, and illustrates most of the features
  185. Xof the grammar metalanguage.
  186. X
  187. X10    (/ > 1    /) "m'u~'"(/ = 1    "[`]")"'o~'i" a
  188. X/    a    (/ > 1    (% = 1    "m[^']ot")(% > 1    c))(/ = 1    c)
  189. X/    c    (% = 5    "l[)]am")(% ~ 5    %)
  190. X100    ...
  191. X
  192. XIt expresses the following:
  193. X
  194. X- For any number greater than or equal to 10, but less
  195. X  than 100, first spell the number divided by ten, if
  196. X  the quotient is greater than one.
  197. X- Print the string "m'u~'".
  198. X- If the quotient is 1, then print the string "[`]".
  199. X- Print the string "'o~'i".
  200. X- Expanding the macro 'a', if the quotient is greater
  201. X  than 1:
  202. X  - If the number modulus the base is 1, print the string "m[^']ot".
  203. X  - If the modulus is greater than 1, expanding macro c:
  204. X    - If the modulus is 5, print "l[)]am".
  205. X    - If the modulus is not 5, evaluate the modulus.
  206. X- If the quotient is 1, expanding macro c:
  207. X  - If the modulus is 5, print "l[)]am".
  208. X  - If the modulus is not 5, evaluate the modulus.
  209. X
  210. XThe essence of all of this is that if, in Vietnamese, something
  211. Xcomes before the word "m'u~'[`]'o~'i", which means 10, it
  212. Xloses its tone ("[`]").  Further, the word for 1 (normally
  213. X"m[^.]ot" changes its tone in some circumstances, and the
  214. Xword for 5 ("n[)]am") changes its initial letter to an "l"
  215. Xin still other situations.  Whew.
  216. X
  217. XMacros can be handy for making very short rules.  For example,
  218. Xin German, 30, 40, etc. are spelled by adding the letters "zig"
  219. Xto the word for the number divided by 10.  Thus, with the
  220. Xfollowing macro:
  221. X
  222. X/    z    "zig"
  223. X
  224. Xthe rule for 30 can be reduced from:
  225. X
  226. X30    "dreizig"
  227. X
  228. Xto:
  229. X
  230. X30    3z
  231. X
  232. X    ::::    Conclusion    ::::
  233. X
  234. XIf you write any grammars, I'd greatly appreciate having
  235. Xthem.  My permanent net address is:
  236. X
  237. X    scott@cerberus.uchicago.edu
  238. X
  239. XUSnail address:
  240. X
  241. X    Scott Deerwester
  242. X    1100 E. 57th, GLS
  243. X    University of Chicago
  244. X    Chicago, Illinois 60637
  245. SHAR_EOF
  246. if test 6275 -ne "`wc -c < 'README'`"
  247. then
  248.     echo shar: error transmitting "'README'" '(should have been 6275 characters)'
  249. fi
  250. fi # end of overwriting check
  251. echo shar: extracting "'Makefile'" '(421 characters)'
  252. if test -f 'Makefile'
  253. then
  254.     echo shar: will not over-write existing file "'Makefile'"
  255. else
  256. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  257. XBINDIR =    /users/lgi/rechdoc/scott/bin
  258. XGRAMMARDIR =    /users/lgi/rechdoc/scott/etc/number
  259. XDEBUG =        -O
  260. XCFLAGS =    $(DEBUG) -DGRAMMARDIR=\"$(GRAMMARDIR)/\"
  261. X
  262. Xnumber:        number.o
  263. X    cc $(DEBUG) number.o -o number
  264. X
  265. Xinstall:    install-number install-lang
  266. X
  267. Xinstall-number:    number
  268. X    install number $(BINDIR)
  269. X
  270. Xinstall-lang:
  271. X    -mkdir $(GRAMMARDIR)
  272. X    (cd lang; tar cf - .) | (cd $(GRAMMARDIR); tar xf -)
  273. X
  274. Xclean:
  275. X    rm -f *.o number *~ core lang/*~
  276. SHAR_EOF
  277. if test 421 -ne "`wc -c < 'Makefile'`"
  278. then
  279.     echo shar: error transmitting "'Makefile'" '(should have been 421 characters)'
  280. fi
  281. fi # end of overwriting check
  282. echo shar: extracting "'number.6'" '(690 characters)'
  283. if test -f 'number.6'
  284. then
  285.     echo shar: will not over-write existing file "'number.6'"
  286. else
  287. sed 's/^X//' << \SHAR_EOF > 'number.6'
  288. X.TH NUMBER 6 "August 11, 1987"
  289. X.AT 3
  290. X.SH NAME
  291. Xnumber \- convert Arabic numerals to natural language
  292. X.SH SYNOPSIS
  293. X.B number
  294. X.I "[language]"
  295. X.SH DESCRIPTION
  296. X.I Number
  297. Xcopies the standard input to the standard output,
  298. Xchanging each decimal number to a fully spelled out version.
  299. XIt works with a lot of languages, among which are English,
  300. XFrench, Chinese, Vietnamese...  If it is given a language
  301. Xthat it doesn't know, it prints out the list of languages
  302. Xthat it does know.  Some languages are listed under more
  303. Xthan one name, such as Gaellic and Irish.
  304. X.SH BUGS
  305. XIt currently doesn't handle very large numbers.  It
  306. Xcould be made to do so, and maybe it will someday.
  307. X.SH AUTHOR
  308. XScott Deerwester
  309. SHAR_EOF
  310. if test 690 -ne "`wc -c < 'number.6'`"
  311. then
  312.     echo shar: error transmitting "'number.6'" '(should have been 690 characters)'
  313. fi
  314. fi # end of overwriting check
  315. echo shar: extracting "'number.c'" '(14405 characters)'
  316. if test -f 'number.c'
  317. then
  318.     echo shar: will not over-write existing file "'number.c'"
  319. else
  320. sed 's/^X//' << \SHAR_EOF > 'number.c'
  321. X#include <stdio.h>
  322. X#include <ctype.h>
  323. X/*
  324. X * number
  325. X *
  326. X *    Number is a program that counts in lots of languages.
  327. X *    It was originally written during a sanity break while
  328. X *    I was writing my PhD thesis.  That version got left
  329. X *    on a machine somewhere in upstate New York.  This one
  330. X *    was done while on leave in Grenoble, after realizing
  331. X *    that I hadn't written a computer program in over two
  332. X *    months.
  333. X *
  334. X *    Number is inspired, of course, from /usr/games/number, but
  335. X *    it uses a series of grammars that define counting in
  336. X *    different languages.  The language that is used to
  337. X *    write the grammars is described below, in evalrule().
  338. X *    If you write any new grammars, I'd greatly appreciate
  339. X *    having them.  Grammars aren't very hard to write, if
  340. X *    you know how to count in something that isn't defined
  341. X *    here.  The longest grammar (french) only has 30 rules
  342. X *    and 5 macros, and correctly pronounces any number less
  343. X *    1,000,000,000,000.  The shortest is for cantonese, which
  344. X *    has 14 rules.
  345. X *
  346. X * A note on the output of number:
  347. X *
  348. X *    The characters that are output conform to the TIRA
  349. X *    character representation standard.  Essentially, strings
  350. X *    in anything except the latin alphabet (what you're reading
  351. X *    now) are preceded by an indication of the alphabet that
  352. X *    they are part of.  The exceptions to this are mandarin,
  353. X *    cantonese and japanese.  These three are written in
  354. X *    pin-yin, roughly Wade Giles, and romanji, respectively.
  355. X *    The only other thing special about this format is that
  356. X *    accents and tone markings are given in [] brackets
  357. X *    before the letter to which they are attached.
  358. X *
  359. X *    TIRA stands for Textual Information Retrieval and Analysis
  360. X *    research group, and is a research group at the University
  361. X *    of Chicago containing computer and information scientists,
  362. X *    literary scholars and linguists.  TIRA is working on a
  363. X *    research environment for doing textual research.  Watch
  364. X *    this space.
  365. X *
  366. X * Copyright 1987, Scott Deerwester.
  367. X *
  368. X *    This code may be freely distributed and copied, provided
  369. X *    that a copy of this notice accompanies all copies and
  370. X *    that no copy is sold for profit.
  371. X */
  372. X
  373. X/*
  374. X *    Constants for array bounds.  Both of these are overkill.
  375. X */
  376. X
  377. X#define    MAXRULES    100
  378. X#define    MAXSPECIALS    50
  379. X
  380. X/*
  381. X *    Structure to hold macro definitions.
  382. X */
  383. X
  384. Xstruct {
  385. X    char    c;
  386. X    char    *rule;
  387. X} specials [MAXSPECIALS];
  388. X
  389. Xint    nspecials = 0;
  390. Xint    maxdigits;
  391. X
  392. X/*
  393. X *    Definition of a grammar rule.
  394. X */
  395. X
  396. Xstruct {
  397. X    int    base;
  398. X#ifdef    COND
  399. X    int    cond;
  400. X#endif    COND
  401. X    char    *rule;
  402. X} rule[MAXRULES];
  403. X
  404. Xint    nrules;
  405. Xchar    *lang = "english";        /* You can change this if you like */
  406. Xchar    *malloc ();
  407. Xunsigned long    parsenumber();
  408. Xlong    atol(), random();
  409. X
  410. Xint    dbgflag = 0;
  411. X
  412. Xmain (argc, argv)
  413. X     char *argv[];
  414. X{
  415. X        int errflg = 0;
  416. X
  417. X    chkdbg ();
  418. X    srandom (getpid ());
  419. X    domaxdigits ();
  420. X/*
  421. X *    Someday, maybe, I'll enable this to take a number
  422. X *    on the command line.
  423. X */
  424. X
  425. X        switch (argc) {
  426. X    case 1:    break;
  427. X    case 2:    lang = argv[1];    break;
  428. X    default:
  429. X        errflg++;
  430. X            break;
  431. X    }
  432. X
  433. X    if (errflg)
  434. X    {
  435. X            fprintf (stderr, "Usage: number [language]\n");
  436. X        exit (0);
  437. X    }
  438. X
  439. X/*
  440. X *    read_grammar finds the grammar for the language and
  441. X *    reads it in.  It exits if it can't find the grammar.
  442. X */
  443. X    read_grammar (lang);
  444. X/*
  445. X *    Main loop.  Read in numbers.  Make sure that the input
  446. X *    is a number, and spell it in the requested language.
  447. X */
  448. X    while (1)
  449. X    {
  450. X        char lbuf [512];
  451. X        register i, l;
  452. X        unsigned long u;
  453. X        long n;
  454. X
  455. X        if (isatty (0))
  456. X            printf ("> ");
  457. X
  458. X        if (!gets (lbuf))
  459. X        {
  460. X            break;
  461. X        }
  462. X
  463. X        if ((l = strlen (lbuf)) > maxdigits)
  464. X        {
  465. X            printf ("My limit is ");
  466. X            for (i = 0; i < maxdigits; i++)
  467. X                putchar ('9');
  468. X            putchar ('\n');
  469. X            continue;
  470. X        } else if (l == 0)
  471. X            continue;
  472. X
  473. X        n = 0;
  474. X        if (sscanf (lbuf, "%ld", &n) != 1)
  475. X        {
  476. X            printf ("%s is not a non-negative integer.\n", lbuf);
  477. X            continue;
  478. X        }
  479. X
  480. X        if (n < 0)
  481. X        {
  482. X            printf ("I don't handle negative numbers.\n");
  483. X            continue;
  484. X        }
  485. X
  486. X        sscanf (lbuf, "%ld", &u);
  487. X        spell (u, 0);
  488. X        outchar ('\n');
  489. X    }
  490. X    outchar ('\n');
  491. X}
  492. X
  493. Xdomaxdigits ()
  494. X{
  495. X    unsigned long maxint = 0;
  496. X    register i;
  497. X    char str [128];
  498. X
  499. X    for (i = 0; i < sizeof (long) * 8; i++)
  500. X        maxint |= 1 << i;
  501. X    sprintf (str, "%lu", maxint);
  502. X    maxdigits = strlen (str) - 1;
  503. X
  504. Xdbg ("domaxdigits computes %lu as %d reliable digits.\n", maxint, maxdigits);
  505. X}
  506. X
  507. X/*
  508. X *    read_to_eol is equivalent to fgets, except that it
  509. X *    reads the string into a temporary buffer, allocates
  510. X *    enough space for it, and copies the string into the
  511. X *    allocated space.  In other words, it does what fgets()
  512. X *    would do if C had proper memory management. :-)
  513. X */
  514. X
  515. Xchar *read_to_eol (fp)
  516. X    FILE *fp;
  517. X{
  518. X    char    *tmpbuf, *cp;
  519. X    char    rbuf [512];
  520. X    register l = 0;
  521. X
  522. X    cp = rbuf;
  523. X    while (1)
  524. X    {
  525. X        fgets (cp, sizeof (rbuf) - l, fp);
  526. X        l = strlen (rbuf);
  527. X        if (rbuf [l - 2] != '\\')
  528. X            break;
  529. X        cp = rbuf + l - 2;
  530. X        if (getc (fp) != '\t')
  531. X        {
  532. X            fprintf (stderr, "read_to_eol didn't find a tab\n");
  533. X            exit (0);
  534. X        }
  535. X        if (l >= sizeof (rbuf))
  536. X        {
  537. X            fprintf (stderr, "rule too long in read_to_eol\n");
  538. X            exit (0);
  539. X        }
  540. X    }
  541. X    
  542. X    tmpbuf = malloc (l = strlen (rbuf));
  543. X    rbuf [l - 1] = '\0';    /* get rid of the newline */
  544. X
  545. X    strcpy (tmpbuf, rbuf);
  546. X
  547. X    return (tmpbuf);
  548. X}
  549. X
  550. X
  551. Xstatic char filename[128];
  552. X
  553. X/*
  554. X *    Cutesy error messages.  They all say the same thing.
  555. X */
  556. X
  557. Xchar *errorfmt[] =
  558. X{
  559. X    "No se habla \"%s\".  Se habla:\n",
  560. X    "I don't speak \"%s\".  I speak:\n",
  561. X    "On ne parle pas \"%s\" ici.  On parle plut[^]ot:\n",
  562. X    "Ich kann nicht \"%s\" sprechen.  Ich spreche:\n",
  563. X    "Ng[?]o [_]m s[^]ik g[']ong \"%s\" w[`]a.  Ng[?]o s[^]ik:\n",
  564. X    "W[?]o b[`]u hu[`]e \"%s\".  W[?]o hu[`]e:\n",
  565. X    "\CYR'Ya' n'ye' govor'yu' po-\"%s\".  'Ya' govor'yu':\n",
  566. X    "Nt[`]e \"%s\" kan m[`]en.  N[`]e be:\n"
  567. X};
  568. X
  569. X#define    nerrfmt    8
  570. X
  571. Xrand (n)
  572. X{
  573. X    return (random () % n);
  574. X}
  575. X
  576. X/*
  577. X *    read_grammar depends on a set of grammar files being
  578. X *    found in GRAMMARDIR.  It expects to find a file with
  579. X *    the name of its parameter, which it opens and reads.
  580. X *    If it can't find one, it prints out a message saying
  581. X *    that it doesn't speak the language, and lists the
  582. X *    known languages by exec'ing /bin/ls.  Note that this
  583. X *    is equivalent to exitting.  It simply puts each of
  584. X *    the rules and macros into arrays.  The format of the
  585. X *    rules in the grammar files is:
  586. X *
  587. X *        n \t rule
  588. X *
  589. X *    where "n" is the base unit of the rule, and "rule"
  590. X *    conforms to the syntax described below in evalrule().
  591. X *    Macros definitions are of the form:
  592. X *
  593. X *        / \t c \t rule
  594. X *
  595. X *    where "c" is the character to be expanded.  The character
  596. X *    must not be a reserved character.
  597. X *
  598. X *    Grammars may also contain comment lines, which begin with
  599. X *    a '#'.
  600. X */
  601. Xread_grammar (lang)
  602. X    char *lang;
  603. X{
  604. X    register i, c;
  605. X    FILE *fp;
  606. X
  607. X    strcat (filename, GRAMMARDIR);
  608. X    strcat (filename, lang);
  609. X
  610. X    if ((fp = fopen (filename, "r")) == NULL)
  611. X    {
  612. X        if ((fp = fopen (lang, "r")) == NULL)
  613. X        {
  614. X            printf (errorfmt [rand (nerrfmt)], lang);
  615. X            execl ("/bin/ls", "number-ls", GRAMMARDIR, 0);
  616. X        }
  617. X    }
  618. X
  619. X    for (i = 0; !feof (fp);)
  620. X    {
  621. X#ifdef    COND
  622. X        rule[i].cond = 0;
  623. X#endif    COND
  624. X
  625. X        if ((c = getc (fp)) == '/')
  626. X        {
  627. X            register j;
  628. X
  629. X            while ((c = getc (fp)) == '\t')
  630. X                ;
  631. X            j = nspecials++;
  632. X            specials[j].c = c;
  633. X            while ((c = getc (fp)) == '\t')
  634. X                ;
  635. X            ungetc (c, fp);
  636. X            specials[j].rule = read_to_eol (fp);
  637. X
  638. Xdbg ("macro '%c': %s\n", specials[j].c, specials[j].rule);
  639. X
  640. X            continue;
  641. X        } else if (c == EOF)
  642. X        {
  643. X            break;
  644. X        } else if (c == '\n')
  645. X        {
  646. X            continue;
  647. X        } else if (c == '#')
  648. X        {
  649. X            while (getc (fp) != '\n')
  650. X                ;
  651. X            continue;
  652. X        } else if (!isdigit (c))
  653. X        {
  654. X            printf ("Read a '%c' in rule %d\n", c, i);
  655. X            break;
  656. X        } else
  657. X            ungetc (c, fp);
  658. X
  659. X        if (fscanf (fp, "%d", &rule[i].base) != 1)
  660. X            break;
  661. X
  662. X        if ((c = getc (fp)) != '\t')
  663. X        {
  664. X#ifdef COND
  665. X            rule[i].cond = c;
  666. X#endif COND
  667. X            while (getc (fp) != '\t')
  668. X                ;
  669. X        }
  670. X
  671. X        rule[i].rule = read_to_eol (fp);
  672. X
  673. Xdbg ("rule %d: %d %s\n", i, rule[i].base, rule[i].rule);
  674. X
  675. X        i++;
  676. X    }
  677. X    nrules = i;
  678. X}
  679. X
  680. X/*
  681. X *    spell is the function called to spell a number.  It
  682. X *    is initially called with condition 'I' (init).  This
  683. X *    is a hack to get around the problem of when to pronounce
  684. X *    0.  Spell essentially just figures out what the appropriate
  685. X *    rule is, and calls evalrule() to do the work.
  686. X */
  687. Xspell (n, level)
  688. X    unsigned long n;
  689. X{
  690. X    register i;
  691. X
  692. X    if (n == 0 && level)
  693. X        return;
  694. X
  695. X    for (i = nrules - 1; rule[i].base > n; i--)
  696. X        ;
  697. X
  698. X    evalrule (rule[i].rule, rule[i].base, n, level);
  699. X}
  700. X
  701. X/*
  702. X * next
  703. X *    This is a simple function to bounce around in strings
  704. X *    with a syntax that includes balanced parens and double
  705. X *    quotes. There's something like this in Icon, but this
  706. X *    program is in C, so...
  707. X */
  708. Xchar *next (s, c)
  709. X    char *s, c;
  710. X{
  711. X    register char *e;
  712. X
  713. X    for (e = s; *e != c; e++)
  714. X    {
  715. X        if (*e == '"')
  716. X            e = next (e + 1, '"');
  717. X        if (*e == '(' && c != '"')
  718. X            e = next (e + 1, ')');
  719. X    }
  720. X    return (e);
  721. X}
  722. X
  723. X/*
  724. X *    evalrule does the dirty work.  It takes a rule, a
  725. X *    base, and a number, and prints the number according
  726. X *    to the rule.  Rules may use the following characters:
  727. X *
  728. X *    B    the base
  729. X *    %    n % base
  730. X *    /    n / base
  731. X *    ,    no-op
  732. X *    "..."    for strings
  733. X *
  734. X *    conditionals are of the form:
  735. X *
  736. X *        (L C R \t rule)
  737. X *
  738. X *    where L and R are either a special character or a
  739. X *    number, and C is one of '>', '<', '=' and '~', meaning,
  740. X *    of course, less than, greater than, equal, and not equal.
  741. X *    Conditionals are evaluated by doconditional(), which
  742. X *    evaluates the condition, and, if it is true, evaluates
  743. X *    the rule.
  744. X *
  745. X *    To give an example of a rule, taken from the grammar
  746. X *    for mandarin:
  747. X *
  748. X *    10    / "sh[']i" %
  749. X *
  750. X *    means that if the largest number that is smaller than
  751. X *    the number we're trying to say is 10, then we say the
  752. X *    number by saying the number divided by 10, followed
  753. X *    by the word "sh[']i", followed by the remainder of the
  754. X *    number divided by ten.  In other words, to say 23,
  755. X *    you say (23 / 10) = 2, then "sh[']i", then (23 % 10) = 3,
  756. X *    or 2 "sh[']i" 3.  After evaluating the rules for 2 and
  757. X *    3, the string "e[`]r sh[']i s[^]an" is printed.
  758. X */
  759. X
  760. Xevalrule (rule, base, n, level)
  761. X    char    *rule;
  762. X    unsigned long    n;
  763. X    int    base, level;
  764. X{    
  765. X    register j, c;
  766. X
  767. Xdbg ("evalrule (\"%s\", %d, %ld)\n", rule, base, n);
  768. X
  769. X    while (c = *rule)
  770. X    {
  771. X        if (isdigit (c))
  772. X        {
  773. X            spell (atol (rule), level + 1);
  774. X            while (isdigit (*++rule))
  775. X                ;
  776. X            continue;
  777. X        } else switch (c) {
  778. X        case ',':    break;
  779. X        case 'B':    spell ((long) base, level + 1);    break;
  780. X        case '%':    spell (n % base, level + 1);    break;
  781. X        case '/':    spell (n / base, level + 1);    break;
  782. X
  783. X        case '"':    while ((c = *++rule) != '"')
  784. X                    outchar (c);
  785. X                break;
  786. X        case '(':    docondition (rule, base, n, level);
  787. X                rule = next (rule + 1, ')');
  788. X                break;
  789. X        default:    for (j = 0; j < nspecials; j++)
  790. X                {
  791. X                    if (specials[j].c == c)
  792. X                    {
  793. X                    evalrule (specials[j].rule, base,
  794. X                          n, level);
  795. X                    break;
  796. X                    }
  797. X                }
  798. X                if (j == nspecials)
  799. X                    outchar (c);
  800. X        }
  801. X        rule++;
  802. X    }
  803. X}
  804. X/*
  805. X *    docondition evaluates conditionals, which are delimited
  806. X *    by parentheses, and which contain two parts: a very
  807. X *    simple Boolean expression and a rule.  The Boolean
  808. X *    expression can, at the moment, only be a simple comparison.
  809. X *    OR's (if the conditions are exclusive) can be done by
  810. X *    putting multiple conditions in a row, and AND's by
  811. X *    making the rule a conditional.  docondition calls
  812. X *    parsecond (parse conditional) to pick out the various
  813. X *    parts of the conditional, evaluates the comparison,
  814. X *    and calls evalrule with the rule as an argument if the
  815. X *    comparison evaluates to true.
  816. X *
  817. X *    Two additional special characters that are accepted here
  818. X *    are:
  819. X *
  820. X *        L    Current recursion level
  821. X *        #    The number itself
  822. X */
  823. Xdocondition (rule, base, n, level)
  824. X    char    *rule;
  825. X    unsigned long    n;
  826. X    int    base, level;
  827. X{
  828. X    char    subrule [128];
  829. X    unsigned long    leftside, rightside;
  830. X    int    truth;
  831. X    char    comparator;
  832. X
  833. X/*
  834. X *    This is to check for bad grammars or buggy parser.
  835. X */
  836. X    if (!parsecond (rule, base, n, level,
  837. X            &leftside, &comparator, &rightside, subrule))
  838. X    {
  839. X        printf ("Gagged on rule \"%s\"\n", rule);
  840. X        return;
  841. X    }
  842. X
  843. X    switch (comparator) {
  844. X    case '>':    truth = leftside > rightside;    break;
  845. X    case '=':    truth = leftside == rightside;    break;
  846. X    case '<':    truth = leftside < rightside;    break;
  847. X    case '~':    truth = leftside != rightside;    break;
  848. X    }
  849. X
  850. Xdbg ("docondition (%d, %d, %d %c %d) -> %s\n",
  851. X    base, n, leftside, comparator, rightside,
  852. X    truth ? subrule : "FAILS");
  853. X
  854. X    if (!truth)
  855. X        return;
  856. X
  857. X    evalrule (subrule, base, n, level);
  858. X}
  859. X
  860. X/*
  861. X *    parsecond parses the rule according to the base,
  862. X *    and assigns the parts to the variables passed
  863. X *    as arguments.
  864. X */
  865. X
  866. Xparsecond (rule, base, n, level, lp, cp, rp, subrule)
  867. X    char    *rule, *cp, *subrule;
  868. X    unsigned long    *lp, *rp, n;
  869. X    int    base, level;
  870. X{
  871. X    char    *index(), *rindex();
  872. X    register char *start, *end;
  873. X    char    leftstring[20], rightstring[20];
  874. X
  875. X    if (sscanf (rule, "(%s %c %s", leftstring, cp, rightstring) != 3)
  876. X    {
  877. X
  878. Xdbg ("parsecond failed sscanf (\"%s\", ...)\n", rule);
  879. X
  880. X        return (0);
  881. X    }
  882. X
  883. X    *rp = parsenumber (rightstring, base, n, level);
  884. X    *lp = parsenumber (leftstring, base, n, level);
  885. X
  886. X    if (!(start = index (rule, '\t')))
  887. X    {
  888. X
  889. Xdbg ("parsecond couldn't find a tab in \"%s\"\n", rule);
  890. X
  891. X        return (0);
  892. X    }
  893. X
  894. X    end = next (++start, ')');
  895. X
  896. X    while (start < end)
  897. X        *subrule++ = *start++;
  898. X        
  899. X    *subrule = '\0';
  900. X    return (1);
  901. X}
  902. X
  903. X/*
  904. X *    parsenumber figures out the numerical value of the
  905. X *    string that it is passed, based on the base and the
  906. X *    number n.
  907. X */
  908. X
  909. Xunsigned long parsenumber (s, base, n, level)
  910. X    unsigned long n;
  911. X    char *s;
  912. X{
  913. X    if (isdigit (s[0]))
  914. X        return (atoi (s));
  915. X
  916. X    switch (s[0]) {
  917. X    case '/':    return (n / base);
  918. X    case '%':    return (n % base);
  919. X    case '#':    return (n);
  920. X    case 'L':    return (level);
  921. X    case 'B':    return (base);
  922. X    default:    fprintf (stderr, "bad number string \"%s\"\n", s);
  923. X            return (-1);
  924. X    }
  925. X}
  926. X
  927. X/*
  928. X *    outchar is a slightly clever version of putchar.  It
  929. X *    won't put a space at the beginning of a line, and it
  930. X *    won't put two spaces in a row.
  931. X */
  932. X
  933. Xoutchar (c)
  934. X{
  935. X    static    lastspace = 0,
  936. X        bol = 1;
  937. X
  938. X    if ((lastspace || bol) && c == ' ')
  939. X        return;
  940. X
  941. X    if (c == '\n')
  942. X        bol = 1;
  943. X    else
  944. X        bol = 0;
  945. X
  946. X    if (c == ' ')
  947. X        lastspace = 1;
  948. X    else
  949. X        lastspace = 0;
  950. X
  951. X    putchar (c);
  952. X}
  953. X
  954. X/*
  955. X *    Well, see, I had this bug, and I left my debugger in
  956. X *    Chicago, and...
  957. X */
  958. X
  959. Xdbg (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  960. X    char *fmt, *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9;
  961. X{
  962. X    int tmpdbgflag = dbgflag;
  963. X
  964. X    if (dbgflag > 0)
  965. X    {
  966. X        dbgflag = 0;
  967. X        fprintf (stderr, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  968. X        dbgflag = tmpdbgflag;
  969. X    }
  970. X}
  971. X
  972. Xchkdbg ()
  973. X{
  974. X    extern char *getenv ();
  975. X    register char *cp;
  976. X
  977. X    if ((dbgflag == 0) && (cp = getenv ("DEBUG=")))
  978. X        dbgflag = atoi (cp);
  979. X}
  980. SHAR_EOF
  981. if test 14405 -ne "`wc -c < 'number.c'`"
  982. then
  983.     echo shar: error transmitting "'number.c'" '(should have been 14405 characters)'
  984. fi
  985. fi # end of overwriting check
  986. if test ! -d 'lang'
  987. then
  988.     echo shar: creating directory "'lang'"
  989.     mkdir 'lang'
  990. fi
  991. echo shar: entering directory "'lang'"
  992. cd 'lang'
  993. echo shar: extracting "'cantonese'" '(386 characters)'
  994. if test -f 'cantonese'
  995. then
  996.     echo shar: will not over-write existing file "'cantonese'"
  997. else
  998. sed 's/^X//' << \SHAR_EOF > 'cantonese'
  999. X#
  1000. X#    Cantonese is a chinese dialect, spoken in Hong
  1001. X#    Kong, the province of Canton, and in many parts
  1002. X#    of the world in Chinese communities.  The following
  1003. X#    rules describes how it is spoken, not written.
  1004. X#
  1005. X0    "ling"
  1006. X1    "y[^]at"
  1007. X2    "y[_]i"
  1008. X3    "s[^]am"
  1009. X4    "sei"
  1010. X5    "[?]ng"
  1011. X6    "l[`]uk"
  1012. X7    "ts[^]at"
  1013. X8    "b[_]aat"
  1014. X9    "g[']ao"
  1015. X10    (/ > 1    /) "s[_]ap" %
  1016. X100    / "b[_]aak" %
  1017. X1000    / "tsin" %
  1018. X10000    / "maan" %
  1019. SHAR_EOF
  1020. if test 386 -ne "`wc -c < 'cantonese'`"
  1021. then
  1022.     echo shar: error transmitting "'cantonese'" '(should have been 386 characters)'
  1023. fi
  1024. fi # end of overwriting check
  1025. echo shar: extracting "'english'" '(372 characters)'
  1026. if test -f 'english'
  1027. then
  1028.     echo shar: will not over-write existing file "'english'"
  1029. else
  1030. sed 's/^X//' << \SHAR_EOF > 'english'
  1031. X0    "zero"
  1032. X1    "one"
  1033. X2    "two"
  1034. X3    "three"
  1035. X4    "four"
  1036. X5    "five"
  1037. X6    "six"
  1038. X7    "seven"
  1039. X8    "eight"
  1040. X9    "nine"
  1041. X/    t    "teen"
  1042. X10    "ten"
  1043. X11    "eleven"
  1044. X12    "twelve"
  1045. X13    "thir"t
  1046. X14    4t
  1047. X15    "fif"t
  1048. X16    6t
  1049. X17    7t
  1050. X18    "eigh"t
  1051. X19    9t
  1052. X20    "twenty" %
  1053. X30    "thirty" %
  1054. X40    "forty" %
  1055. X50    "fifty" %
  1056. X60    6"ty" %
  1057. X70    7"ty" %
  1058. X80    8"y" %
  1059. X90    9"ty" %
  1060. X100    / "hundred" %
  1061. X1000    / "thousand" %
  1062. X1000000    / "million" %
  1063. X1000000000    / "billion" %
  1064. SHAR_EOF
  1065. if test 372 -ne "`wc -c < 'english'`"
  1066. then
  1067.     echo shar: error transmitting "'english'" '(should have been 372 characters)'
  1068. fi
  1069. fi # end of overwriting check
  1070. echo shar: extracting "'french'" '(1026 characters)'
  1071. if test -f 'french'
  1072. then
  1073.     echo shar: will not over-write existing file "'french'"
  1074. else
  1075. sed 's/^X//' << \SHAR_EOF > 'french'
  1076. X#
  1077. X#    French
  1078. X#
  1079. X0    zero
  1080. X1    "un"
  1081. X2    "deux"
  1082. X3    "trois"
  1083. X4    "quatre"
  1084. X5    "cinq"
  1085. X6    "six"
  1086. X7    "sept"
  1087. X8    "huit"
  1088. X9    "neuf"
  1089. X10    "dix"
  1090. X11    "onze"
  1091. X12    "douze"
  1092. X13    "treize"
  1093. X14    "quatorze"
  1094. X15    "quinze"
  1095. X16    "seize"
  1096. X17    "dix-sept"
  1097. X18    "dix-huit"
  1098. X19    "dix-neuf"
  1099. X20    "vingt" R
  1100. X30    "trente" R
  1101. X40    "quarante" R
  1102. X50    "cinquante" R
  1103. X60    "soixante" R
  1104. X#
  1105. X#    For 80, there is no "et" before either 1 or 11.
  1106. X#    For 60, there is an "et" before both.
  1107. X#
  1108. X80    "quatre-vingt"S %
  1109. X100    D "cent"* %
  1110. X1000    D "mille" %
  1111. X1000000    / "million"* %
  1112. X1000000000    / "milliard"* %
  1113. X/    *    (/ > 1    S)
  1114. X#
  1115. X#    This rule takes care of the "s" after "cent" or "quatre-vingt".
  1116. X#    The former takes an "s" when "/" is greater than one, and
  1117. X#    there is no remainder.  The latter (naturally!) only when
  1118. X#    there is no remainder.
  1119. X#
  1120. X/    S    (% = 0    "s")
  1121. X#
  1122. X#    For numbers between 20 and 99, if the remainder is one,
  1123. X#    the word "et" (and) is added between the word for the
  1124. X#    factor of ten, and the word for the remainder.
  1125. X#
  1126. X/    R    (% = 1    "et ")(% = 11    "et ")%
  1127. X#
  1128. X#    For 100 and 1000, / is only written if it is greater
  1129. X#    than one.
  1130. X#
  1131. X/    D    (/ > 1    /)
  1132. SHAR_EOF
  1133. if test 1026 -ne "`wc -c < 'french'`"
  1134. then
  1135.     echo shar: error transmitting "'french'" '(should have been 1026 characters)'
  1136. fi
  1137. fi # end of overwriting check
  1138. echo shar: extracting "'german'" '(354 characters)'
  1139. if test -f 'german'
  1140. then
  1141.     echo shar: will not over-write existing file "'german'"
  1142. else
  1143. sed 's/^X//' << \SHAR_EOF > 'german'
  1144. X1    "zero"
  1145. X1    "ein"
  1146. X2    "zwei"
  1147. X3    "drei"
  1148. X4    "vier"
  1149. X5    "f[:]unf"
  1150. X6    "sechs"
  1151. X7    "sieben"
  1152. X8    "acht"
  1153. X9    "neun"
  1154. X10    "zehn"
  1155. X11    "elf"
  1156. X12    "zw[:]olf"
  1157. X13    3,10
  1158. X14    4,10
  1159. X15    5,10
  1160. X16    "sech"10
  1161. X17    "sieb"10
  1162. X18    8,10
  1163. X19    9,10
  1164. X/    z    "zig"
  1165. X20    *"zwant"z
  1166. X30    *3z
  1167. X40    *4z
  1168. X50    *5z
  1169. X60    *"sech"z
  1170. X70    *"sieb"z
  1171. X80    *8z
  1172. X90    *9z
  1173. X100    / "hundert" %
  1174. X1000    / "tausend" %
  1175. X1000000    / "million" %
  1176. X/    *    (% > 0    % "und ")
  1177. SHAR_EOF
  1178. if test 354 -ne "`wc -c < 'german'`"
  1179. then
  1180.     echo shar: error transmitting "'german'" '(should have been 354 characters)'
  1181. fi
  1182. fi # end of overwriting check
  1183. echo shar: extracting "'irish'" '(483 characters)'
  1184. if test -f 'irish'
  1185. then
  1186.     echo shar: will not over-write existing file "'irish'"
  1187. else
  1188. sed 's/^X//' << \SHAR_EOF > 'irish'
  1189. X#
  1190. X#    Irish, or Gaellic.  Thanks to Alexis Donnelly for
  1191. X#    serving as linguistic informant.
  1192. X#
  1193. X1    "aon"
  1194. X2    "d[']o"
  1195. X3    "tr[']i"
  1196. X4    "ceathair"
  1197. X5    "c[']uig"
  1198. X6    "s[']e"
  1199. X7    "seacht"
  1200. X8    "ocht"
  1201. X9    "nao[']i"
  1202. X10    (# = 10    "deich")(# > 10    "a" b "d[']eag")
  1203. X20    "fiche" b
  1204. X30    "tr[']iocha" b
  1205. X40    "daichead" c
  1206. X50    "caogo" b
  1207. X60    "seasca" b
  1208. X70    "seachta" b
  1209. X80    "ocht[']o" b
  1210. X90    "n[']ocha" b
  1211. X100    d "c"h"[']ead" c
  1212. X1000    d "m[']ile" %
  1213. X/    a    (% > 0    " a ")
  1214. X/    b    (% = 1    "h")%
  1215. X/    c    (% = 1    "ah")%
  1216. X/    d    (/ > 1    /)
  1217. X/    h    (/ ~ 1    (/ ~ 4    "h"))
  1218. SHAR_EOF
  1219. if test 483 -ne "`wc -c < 'irish'`"
  1220. then
  1221.     echo shar: error transmitting "'irish'" '(should have been 483 characters)'
  1222. fi
  1223. fi # end of overwriting check
  1224. echo shar: extracting "'japanese'" '(598 characters)'
  1225. if test -f 'japanese'
  1226. then
  1227.     echo shar: will not over-write existing file "'japanese'"
  1228. else
  1229. sed 's/^X//' << \SHAR_EOF > 'japanese'
  1230. X#
  1231. X#    Japanese, written in romanji.  Thanks to Malcolm
  1232. X#    Bennett for providing the grammar that I got this
  1233. X#    out of, and for debugging it.
  1234. X#
  1235. X0    "r[']ei"
  1236. X1    "ich[']i"
  1237. X2    "n[']i"
  1238. X3    "san"
  1239. X4    "y[']on"
  1240. X5    "g[']o"
  1241. X6    "rok[']u"
  1242. X7    "n[']ana"
  1243. X8    "hach[']i"
  1244. X9    "ku[']u"
  1245. X10    b"j[-]u"a
  1246. X100    c
  1247. X200    "ni"c
  1248. X300    "s[']am"c
  1249. X400    "y[']on"c
  1250. X500    "go"c
  1251. X600    "roppyak[']u" %
  1252. X700    "nan[']ahyaku" %
  1253. X800    "happyak[']u" %
  1254. X1000    m
  1255. X2000    "ni"m
  1256. X3000    "sanz[']en" %
  1257. X4000    "yon"m
  1258. X5000    "go"m
  1259. X6000    "roku"m
  1260. X7000    "nana"m
  1261. X8000    "has"m
  1262. X9000    "kyu[']"m
  1263. X10000    e"m[']an" %
  1264. X/    c    "hyak[']u" %
  1265. X/    m    "s[']en" %
  1266. X/    b    (/ > 1    /)
  1267. X/    a    (/ > 1    " ")%
  1268. X/    e    (/ = 3    "sam")(/ ~ 3    /)
  1269. SHAR_EOF
  1270. if test 598 -ne "`wc -c < 'japanese'`"
  1271. then
  1272.     echo shar: error transmitting "'japanese'" '(should have been 598 characters)'
  1273. fi
  1274. fi # end of overwriting check
  1275. echo shar: extracting "'mandarin'" '(205 characters)'
  1276. if test -f 'mandarin'
  1277. then
  1278.     echo shar: will not over-write existing file "'mandarin'"
  1279. else
  1280. sed 's/^X//' << \SHAR_EOF > 'mandarin'
  1281. X0    "l[']in"
  1282. X1    "y[^]i"
  1283. X2    "e[`]r"
  1284. X3    "s[^]an"
  1285. X4    "s[`]i"
  1286. X5    "w[?]u"
  1287. X6    "l[`]iu"
  1288. X7    "q[^]i"
  1289. X8    "b[^]a"
  1290. X9    "ji[?]u"
  1291. X10    (/ > 1    /) "sh[']i" %
  1292. X100    / "b[?]ai" %
  1293. X1000    / "qi[^]an" %
  1294. X10000    / "w[`]an" %
  1295. X100000000    / "y[`]i" %
  1296. SHAR_EOF
  1297. if test 205 -ne "`wc -c < 'mandarin'`"
  1298. then
  1299.     echo shar: error transmitting "'mandarin'" '(should have been 205 characters)'
  1300. fi
  1301. fi # end of overwriting check
  1302. echo shar: extracting "'romanian'" '(420 characters)'
  1303. if test -f 'romanian'
  1304. then
  1305.     echo shar: will not over-write existing file "'romanian'"
  1306. else
  1307. sed 's/^X//' << \SHAR_EOF > 'romanian'
  1308. X#
  1309. X#    Romanian
  1310. X#
  1311. X0    "zero"
  1312. X1    "unu"
  1313. X2    "doi"
  1314. X3    "trei"
  1315. X4    "patru"
  1316. X5    "cinci"
  1317. X6    "[,]sase"
  1318. X7    "[,]sapte"
  1319. X8    "opt"
  1320. X9    "nou[)]a"
  1321. X10    (% > 0    %"spre")"zece"
  1322. X/    z    "zeci" a
  1323. X20    "dou[)]a"z
  1324. X30    3z
  1325. X40    4z
  1326. X50    5z
  1327. X60    "[,]sai"z
  1328. X70    7z
  1329. X80    8z
  1330. X90    9z
  1331. X100    (/ = 1    "o sut[)]a")(/ > 1    g "sute") %
  1332. X1000    (/ = 1    "o mie")(/ > 1    g f "mii") %
  1333. X1000000    g f "milio"s %
  1334. X/    a    (% > 0    "[,]si") %
  1335. X/    f    (/ > 19    "de")
  1336. X/    g    (/ = 2    "dou[)]a")(/ ~ 2    /)
  1337. X/    s    (/ > 1    "ane")(/ = 1    "n")
  1338. SHAR_EOF
  1339. if test 420 -ne "`wc -c < 'romanian'`"
  1340. then
  1341.     echo shar: error transmitting "'romanian'" '(should have been 420 characters)'
  1342. fi
  1343. fi # end of overwriting check
  1344. echo shar: extracting "'vietnamese'" '(347 characters)'
  1345. if test -f 'vietnamese'
  1346. then
  1347.     echo shar: will not over-write existing file "'vietnamese'"
  1348. else
  1349. sed 's/^X//' << \SHAR_EOF > 'vietnamese'
  1350. X#
  1351. X#    Vietnamese.
  1352. X#
  1353. X0    "kh[^]ong"
  1354. X1    "m[.^]ot"
  1355. X2    "hai"
  1356. X3    "ba"
  1357. X4    "b['^]on"
  1358. X5    "n[)]am"
  1359. X6    "s[']au"
  1360. X7    "b[~]ay"
  1361. X8    "t[']am"
  1362. X9    "ch[']in"
  1363. X10    (/ > 1    /) "m'u~'"(/ = 1    "[`]")"'o~'i" a
  1364. X100    / "tr[)]am" d
  1365. X1000    / "ng[`]an" d
  1366. X1000000    / "tri[^.]eu" d
  1367. X/    a    (/ > 1    (% = 1    "m[^']ot")(% > 1    c))(/ = 1    c)
  1368. X/    c    (% = 5    "l[)]am")(% ~ 5    %)
  1369. X/    d    (% < 10    (% > 0    (L = 0    "l[~]e"))) %
  1370. SHAR_EOF
  1371. if test 347 -ne "`wc -c < 'vietnamese'`"
  1372. then
  1373.     echo shar: error transmitting "'vietnamese'" '(should have been 347 characters)'
  1374. fi
  1375. fi # end of overwriting check
  1376. echo shar: extracting "'malinke'" '(461 characters)'
  1377. if test -f 'malinke'
  1378. then
  1379.     echo shar: will not over-write existing file "'malinke'"
  1380. else
  1381. sed 's/^X//' << \SHAR_EOF > 'malinke'
  1382. X#
  1383. X#    Malinke is spoken is western Africa.  It is known as
  1384. X#    either malinke, maninka, mandingo or djula.  This
  1385. X#    grammar thanks to Ibrahima Sakho, who served as
  1386. X#    linguistic informant.
  1387. X#
  1388. X0    "foi"
  1389. X1    "k[']el[']en"
  1390. X2    "fila"
  1391. X3    "saba"
  1392. X4    "nani"
  1393. X5    "lolu"
  1394. X6    "w[:]or[:]o"
  1395. X7    "w[:]or[:]owila"
  1396. X8    "s[']egin"
  1397. X9    "k[:]on[:]ond[:]o"
  1398. X10    t
  1399. X100    h
  1400. X1000    "wa" / r
  1401. X10000    "wa" t
  1402. X100000    "wa" h
  1403. X/    r    (% > 0    "ni" %)
  1404. X/    t    (/ = 1    "tan")(/ = 2    "mugan")(/ > 2    "bi"/) r
  1405. X/    h    "k[`]em[`]e" (/ > 1    /) r
  1406. SHAR_EOF
  1407. if test 461 -ne "`wc -c < 'malinke'`"
  1408. then
  1409.     echo shar: error transmitting "'malinke'" '(should have been 461 characters)'
  1410. fi
  1411. fi # end of overwriting check
  1412. echo shar: extracting "'spanish'" '(670 characters)'
  1413. if test -f 'spanish'
  1414. then
  1415.     echo shar: will not over-write existing file "'spanish'"
  1416. else
  1417. sed 's/^X//' << \SHAR_EOF > 'spanish'
  1418. X#
  1419. X#    Spanish.  Thanks to Hugo Ramos for serving as linguistic
  1420. X#    informant.
  1421. X#
  1422. X0    "cero"
  1423. X1    "uno"
  1424. X2    "dos"
  1425. X3    "tres"
  1426. X4    "cuatro"
  1427. X5    "cinco"
  1428. X6    "seis"
  1429. X7    "siete"
  1430. X8    "ocho"
  1431. X9    "nueve"
  1432. X10    "diez"
  1433. X11    "once"
  1434. X12    "doce"
  1435. X13    "trece"
  1436. X14    "catorce"
  1437. X15    "quince"
  1438. X/    d    "dieci"
  1439. X16    d6
  1440. X17    d7
  1441. X18    d8
  1442. X19    d9
  1443. X20    (% = 0    "veinte")(% > 0    "venti"%)
  1444. X30    "treinta" r
  1445. X/    r    (% > 0    "y" %)
  1446. X/    a    "enta" r
  1447. X40    "cuar"a
  1448. X50    "cincu"a
  1449. X60    "ses"a
  1450. X70    "set"a
  1451. X80    "och"a
  1452. X90    "nov"a
  1453. X100    (/ = 2    "do")\
  1454. X    (/ = 3    "tre")\
  1455. X    (/ = 4    /)\
  1456. X    (/ = 5    "quin")\
  1457. X    (/ = 6    "sei")\
  1458. X    (/ = 7    "sete")\
  1459. X    (/ = 8    /)\
  1460. X    (/ = 9    "nove")\
  1461. X    (/ ~ 5    "c")"ien"(/ > 1    "tos")(/ = 1    (% > 0    "to")) %
  1462. X1000    (/ > 1    /) "mil" %
  1463. X1000000    (/ = 1    "un")(/ ~ 1    /) "millon"(/ > 1    "es") %
  1464. SHAR_EOF
  1465. if test 670 -ne "`wc -c < 'spanish'`"
  1466. then
  1467.     echo shar: error transmitting "'spanish'" '(should have been 670 characters)'
  1468. fi
  1469. fi # end of overwriting check
  1470. echo shar: extracting "'pular'" '(384 characters)'
  1471. if test -f 'pular'
  1472. then
  1473.     echo shar: will not over-write existing file "'pular'"
  1474. else
  1475. sed 's/^X//' << \SHAR_EOF > 'pular'
  1476. X#
  1477. X#    Pular is spoken in western Africa.  Also called Fulani.
  1478. X#
  1479. X0    "fus"
  1480. X1    "g[:]o"
  1481. X2    "dhidhi"
  1482. X3    "tati"
  1483. X4    "nai"
  1484. X5    (# = 5    "dyowi")(# ~ 5    "dy[`]e"%)
  1485. X10    t R
  1486. X100    h R
  1487. X1000    (/ = 1    "wulur[`]e")(/ > 1    g /) R
  1488. X10000    g t R
  1489. X100000    g h R
  1490. X/    g    "guludy[`]e"
  1491. X/    t    (/ = 1    "sap[:]o")\
  1492. X    (/ = 2    "n[:]ogai")\
  1493. X    (/ > 2    "tyapannd[`]e" /)
  1494. X/    h    "t[`]em[`]e"(/ = 1    "d[`]er[`]e")(/ > 1    "dh[`]e "/)
  1495. X/    R    (% > 0    "[']e" %)
  1496. SHAR_EOF
  1497. if test 384 -ne "`wc -c < 'pular'`"
  1498. then
  1499.     echo shar: error transmitting "'pular'" '(should have been 384 characters)'
  1500. fi
  1501. fi # end of overwriting check
  1502. echo shar: extracting "'susu'" '(342 characters)'
  1503. if test -f 'susu'
  1504. then
  1505.     echo shar: will not over-write existing file "'susu'"
  1506. else
  1507. sed 's/^X//' << \SHAR_EOF > 'susu'
  1508. X#
  1509. X#    Susu is spoken in Guinea.  Also called soso.
  1510. X#
  1511. X1    "k[']er[']en"
  1512. X2    "firin"
  1513. X3    "sakhan"
  1514. X4    "nani"
  1515. X5    "suli"
  1516. X6    "s[']enni"
  1517. X7    "solof[']er[']e"
  1518. X8    "solomasakhan"
  1519. X9    "solomanani"
  1520. X10    t R
  1521. X100    h R
  1522. X1000    "wulu" / R
  1523. X10000    "wulu" t R
  1524. X100000    "wulu" h R
  1525. X/    t    (/ = 1    "fu")\
  1526. X    (/ = 2    "mukhain")\
  1527. X    (/ > 2    "tongo" /) R
  1528. X/    h    "k[`]em[`]e" (/ > 1    /)
  1529. X/    R    (% > 0    "nun" %)
  1530. SHAR_EOF
  1531. if test 342 -ne "`wc -c < 'susu'`"
  1532. then
  1533.     echo shar: error transmitting "'susu'" '(should have been 342 characters)'
  1534. fi
  1535. fi # end of overwriting check
  1536. echo shar: linking "'chinese'" to "'mandarin'"
  1537. if test -f 'chinese'
  1538. then
  1539.     echo shar: will not over-write existing file "'chinese'"
  1540. else
  1541.     ln 'mandarin' 'chinese'
  1542. fi # end of overwriting check
  1543. echo shar: extracting "'italian'" '(531 characters)'
  1544. if test -f 'italian'
  1545. then
  1546.     echo shar: will not over-write existing file "'italian'"
  1547. else
  1548. sed 's/^X//' << \SHAR_EOF > 'italian'
  1549. X#
  1550. X#    Italian.  This grammar thanks to a week and a half
  1551. X#    in Italy, and a Berlitz phrase book!
  1552. X#
  1553. X0    "zero"
  1554. X1    "uno"
  1555. X2    "due"
  1556. X3    "tre"
  1557. X4    "quattro"
  1558. X5    "cinque"
  1559. X6    "sei"
  1560. X7    "sette"
  1561. X8    "otto"
  1562. X9    "nove"
  1563. X10    "dieci"
  1564. X11    "un"d
  1565. X12    "do"d
  1566. X13    3d
  1567. X14    4d
  1568. X15    "quin"d
  1569. X16    "se"d
  1570. X17    d"a"7
  1571. X18    d8
  1572. X19    d"a"9
  1573. X20    "vent"ir
  1574. X/    d    "dici"
  1575. X/    r    (% > 0    %)
  1576. X/    i    (% ~ 1    (% ~ 8    "i"))
  1577. X/    a    (% ~ 1    "a")
  1578. X30    "trent"ar
  1579. X40    "quarant"ar
  1580. X50    "cinquant"ar
  1581. X60    "sessant"ar
  1582. X70    "septant"ar
  1583. X80    "ottant"ar
  1584. X90    "novant"ar
  1585. X100    (/ > 1    /)"cento"%
  1586. X1000    (/ = 1    "mille")(/ > 1    /"mila")%
  1587. X1000000    /"milione"%
  1588. SHAR_EOF
  1589. if test 531 -ne "`wc -c < 'italian'`"
  1590. then
  1591.     echo shar: error transmitting "'italian'" '(should have been 531 characters)'
  1592. fi
  1593. fi # end of overwriting check
  1594. echo shar: linking "'gaellic'" to "'irish'"
  1595. if test -f 'gaellic'
  1596. then
  1597.     echo shar: will not over-write existing file "'gaellic'"
  1598. else
  1599.     ln 'irish' 'gaellic'
  1600. fi # end of overwriting check
  1601. echo shar: extracting "'esperanto'" '(158 characters)'
  1602. if test -f 'esperanto'
  1603. then
  1604.     echo shar: will not over-write existing file "'esperanto'"
  1605. else
  1606. sed 's/^X//' << \SHAR_EOF > 'esperanto'
  1607. X#
  1608. X#    Esperanto
  1609. X#
  1610. X0    "zero"
  1611. X1    "unu"
  1612. X2    "du"
  1613. X3    "tri"
  1614. X4    "kvar"
  1615. X5    "kvin"
  1616. X6    "ses"
  1617. X7    "sep"
  1618. X8    "ok"
  1619. X9    "na[bre]u"
  1620. X10    d"dek" %
  1621. X100    d "cent" %
  1622. X/    d    (/ > 1    /)
  1623. X1000    d "mil" %
  1624. SHAR_EOF
  1625. if test 158 -ne "`wc -c < 'esperanto'`"
  1626. then
  1627.     echo shar: error transmitting "'esperanto'" '(should have been 158 characters)'
  1628. fi
  1629. fi # end of overwriting check
  1630. echo shar: done with directory "'lang'"
  1631. cd ..
  1632. #    End of shell archive
  1633. exit 0
  1634.  
  1635. -- 
  1636.  
  1637. Rich $alz
  1638. Cronus Project, BBN Labs            rsalz@bbn.com
  1639. Moderator, comp.sources.unix            sources@uunet.uu.net
  1640.